package com.stackoverflow;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.sf.stackwrap4j.Meta;
import net.sf.stackwrap4j.ServerFault;
import net.sf.stackwrap4j.StackWrapper;
import net.sf.stackwrap4j.StackOverflow;
import net.sf.stackwrap4j.SuperUser;
import net.sf.stackwrap4j.entities.Answer;
import net.sf.stackwrap4j.entities.Question;
import net.sf.stackwrap4j.entities.Tag;
import net.sf.stackwrap4j.entities.User;
import net.sf.stackwrap4j.exceptions.ParameterNotSetException;
import net.sf.stackwrap4j.json.JSONException;
import net.sf.stackwrap4j.query.PageQuery;
import net.sf.stackwrap4j.query.QuestionQuery;
import net.sf.stackwrap4j.query.SearchQuery;
import net.sf.stackwrap4j.query.TaggedQuery;
import net.sf.stackwrap4j.query.UserQuery;
import net.sf.stackwrap4j.query.UserQuestionQuery;

public class Retriever {
	private StackWrapper sw;
	private PageQuery query;
	private static Retriever uniqueInstance;
	private Profile profile;
	
	private Retriever() {
		profile = new Profile();
	}
	
	public static Retriever getInstance() {
		 if (uniqueInstance == null) {
			 uniqueInstance = new Retriever();
		 }
		 return uniqueInstance;
	}
	
	public void setSite(String siteName) {
		String api_key = "sYsdqsn_6UKvWjnUqV7OFw";
		
		if (siteName.equals("stackoverflow"))
		{
			sw = new StackOverflow(api_key);
			profile.setPreferenceKey("stackOverflowProfile");
		}
		else if (siteName.equals("metastackoverflow"))
		{
			sw = new Meta(api_key);
			profile.setPreferenceKey("metaProfile");
		}
		else if (siteName.equals("serverfault"))
		{
			sw = new ServerFault(api_key);
			profile.setPreferenceKey("serverFaultProfile");
		}
		else if (siteName.equals("superuser"))
		{
			sw = new SuperUser(api_key);
			profile.setPreferenceKey("superUserProfile");
		}
	}
	
	public Profile getProfile()
	{
		return profile;
	}
	
	public List<ListItem> getQuestions(String tag)
	{
		List<ListItem> items = new ArrayList<ListItem>();
		List<Question> questions = null;
		
		try {
			if (query == null)
			{
				if (tag != null)
				{
					if (tag.startsWith("{search}"))
					{
						query = new SearchQuery();
						tag = tag.substring("{search}".length(), tag.length());
						((TaggedQuery) query).setTags(tag);
						query.setPageSize(10);
						query.setSort(SearchQuery.Sort.activity());
						questions = sw.search((SearchQuery) query);
					}
					else if (tag.startsWith("{user}"))
					{
						query = new UserQuestionQuery();
						query.setSort(UserQuestionQuery.Sort.creation());
						query.setPage(10);
						int userId = Integer.parseInt((tag.substring(";ID=".length()+tag.indexOf(";ID="), tag.length())));
						((UserQuestionQuery)query).addId(userId);
						//questions = sw.getQuestionsByUserId((UserQuestionQuery)query);
						questions = sw.getQuestionsByUserId(userId);
					}
				}
			}
			if (query == null)
			{
				query = new QuestionQuery();
			}
			
			if (questions == null)
			{
				if (query instanceof SearchQuery)
				{
					questions = sw.search((SearchQuery) query);
				}
				else if (query instanceof UserQuestionQuery)
				{
					questions = sw.getQuestionsByUserId((UserQuestionQuery)query);
				}
				else
				{
					//query = new QuestionQuery();
					query.setSort(QuestionQuery.Sort.creation());
					if (tag != null)
						((TaggedQuery) query).setTags(tag);
			    	query.setPageSize(10);
			    	questions = sw.listQuestions((QuestionQuery) query);
				}
			}
			
			for (Question r : questions)
			{
				// check if the user that posted this item has deleted their account (no owner)
				String owner;
				if (r.getOwner() != null)
				{
					owner = r.getOwner().getDisplayName();
				}
				else
				{
					owner = "_DELETED_ACCOUNT_";
				}
				String body;
				if (r.getBody() == null)
				{
					body = sw.getQuestionById(r.getPostId()).getBody();
				}
				else
				{
					body = r.getBody();
				}
				items.add(new ListItem(r.getTitle(), body, r.getScore(), owner, r.getPostId()));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParameterNotSetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return items;
	}
	
	public List<ListItem> getAnswers(int questionId)
	{
		List<ListItem>items = new ArrayList<ListItem>();
		List<Answer> answers;
		
		try {
			answers = sw.getAnswersByQuestionId(questionId);
			
			for (Answer r : answers)
			{
				// check if the user that posted this item has deleted their account (no owner)
				String owner;
				if (r.getOwner() != null)
				{
					owner = r.getOwner().getDisplayName();
				}
				else
				{
					owner = "_DELETED_ACCOUNT_";
				}
				items.add(new ListItem("", r.getBody(), r.getScore(), owner, r.getPostId()));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return items;
	}
	
	public boolean incrementPage() {
		query.incrementPage();
		return true;
	}
	
	public boolean decrementPage() {
		if (query.getPage() > 1)
		{
			query.decrementPage();
			return true;
		}
		else
		{
			return false;
		}
	}
	
	public List<String> getTopTags()
	{
		List<Tag> tagList = null;
		List<String> result = new ArrayList<String>();
		
		try {
			 tagList = sw.listTags();
			 for (Tag t: tagList)
			 {
				 result.add(t.getName() + ", "+t.getCount()+" questions");
			 }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
	}
	
	public List<ListItem> getUsersByName(UserQuery query)
	{
		List<User> userList = null;
		List<ListItem> result = new ArrayList<ListItem>();
		
		try {
			 userList = sw.listUsers(query);
			 for (User u: userList)
			 {
				 result.add(new ListItem("", "", u.getReputation(), u.getDisplayName(), u.getId()));
			 }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
	}
	
	public void clearQuery()
	{
		query = null;
	}
}
